package com.example.designpattern.factory.factoryMethodDesign;

import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @program: DesignPattern
 * @description: 工厂
 * @author: zhangjt
 * @create: 2024-11-15 17:20
 **/

/*
*
缺点：
反射开销：

使用反射动态加载类和创建对象会增加一定的性能开销，特别是在资源类型很多时，可能会影响性能。反射操作是较为耗时的，因此在性能敏感的应用中可能需要考虑其他优化方式。
缺乏类型检查：

反射无法提供编译时的类型安全。你传入一个错误的 type 字符串时，工厂不会抛出编译时错误，而是在运行时才会抛出异常（比如 ClassNotFoundException 或 InstantiationException）。这可能导致潜在的运行时错误，并且不容易调试。
配置文件依赖：

你的工厂类依赖于外部配置文件，配置文件中的错误（如类名拼写错误或路径错误）会导致程序启动时出现异常。这要求配置文件的准确性和完整性非常高，否则会影响应用的稳定性。
难以追踪：

由于所有类型的对象都是通过反射来加载的，调试和追踪这些对象的创建和生命周期变得更加困难，特别是当错误发生时，栈跟踪中可能不容易看到具体的问题所在。
违反了开闭原则（OCP）：

如果配置文件中的类发生变化，你需要手动修改配置文件。虽然不需要修改代码，但是对配置文件的修改仍然会影响系统的行为，且每次需要修改配置文件以支持新的类型。相比之下，工厂方法模式或抽象工厂模式能够更好地遵守开闭原则，通过扩展新的类而非修改配置来增加新类型。
* */
@Slf4j
public class Factory {
    private static Map<String, Resource> factoryInfo = new HashMap<>();


    static {
        Properties properties = new Properties();
        InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("factoryProperties.properties");
        log.info("加载配置文件");
        if (resourceAsStream != null) {
            try {
                properties.load(resourceAsStream);
                for (Object key : properties.keySet()) {
                    String className = properties.getProperty(key.toString());
                    Class<?> aClass = Class.forName(className);
                    Resource resource = (Resource) aClass.newInstance();
                    factoryInfo.put(key.toString(), resource);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

    }

    public static Resource createResource(String type) {
        return factoryInfo.get(type);
    }
}
